package com.test.test.thread;

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * volatile 非原子型 测试 
 * volatile （不需要加锁）比synchronized 执行效率高
 * 解决方式有三种
 * 	synchronized 是原子型的  AtomicInteger  
 * 	java.util.concurrent.locks.ReentrantLock
 * 	java.util.concurrent.atomic.AtomicInteger 避免使用synchronized 性能非常高
 * @author zx
 *
 */
public  class VolatileTestNotAtomic {
	
	private Lock lock = new ReentrantLock();
	volatile AtomicInteger  num = new AtomicInteger(0);
	public void numAdd() {
		try {
			Thread.sleep(100);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		/**
		 * 第一种 解决方法
		 * synchronized (this) {
		 * 
		 * }
		 */
//		synchronized (this) {
//			num ++;
//		}
		/**
		 * 第二种 解决方法
		 *  Lock
		 */
//		lock.lock();
//		try {
//			num ++;
//		} finally {
//			//锁一定会释放
//			lock.unlock();
//		}
		/**
		 * 第三种 解决方法
		 *  AtomicInteger
		 */
		num.getAndIncrement();
		//num ++;
	}
	
	
	public int getNum() {
		return num.get() ;
	}
	/**
	 * volatile 非原子型
	 * @param args
	 */
   public static void main(String[] args) {
	   VolatileTestNotAtomic a = new VolatileTestNotAtomic();
	   for (int i = 0; i < 500; i++) {
		    new Thread(new Runnable() {
			    @Override
				public void run() {
					a.numAdd();
				}
		}) .start();
	   }
	   while (Thread.activeCount()>1) {
		   Thread.yield();
	   }
	   //单用volatile 结果不一定是500 原因  volatile 非原子型
	   // num ++ 的 执行过程  1、从内存中读取  num 值   2、执行 num ++ 3、把num++后 的值写会 内存中
	   // 
	   /**
	    * 执行过程中  会出现  假如内存中的 num =5
	    * 1、线程A 获取到num的值 5并copy到了工作内存中 丢失cpu资源
	    * 2、线程B 获取到cpu资源  并读取到了 内存中的值5 
	    * 3、线程B 执行了num ++ 得到结果 并更新到了主内存中（volatile 特性）线程结束
	    * 4、这时 线程A 获取到了cpu资源  （线程A工作内存中的值当前为5）  执行num++得到结果 并更新到了主内存中 线程结束
	    * 5、这时 num 在主内存中的值为6 实际执行了2次 num++ 应该为 7
	    */
	   System.out.println(a.getNum());
   }
}
